import json
import logging
import os
import shutil
import subprocess
import tempfile
import time
import traceback
from concurrent.futures import ProcessPoolExecutor
from typing import Any, Callable, Dict, Optional

from django.conf import settings

logger = logging.getLogger(__name__)

# 语言名称映射到目录名称
language_dir_map = {
    'python': 'static/api/py',
    'javascript': 'static/api/js',
    'typescript': 'static/api/ts',
    'lua': 'static/api/lua',
}
language_names = {
    'python': 'Python',
    'javascript': 'JavaScript',
    'typescript': 'TypeScript',
    'lua': 'Lua',
}
user_code_dir_name = 'game/'
snippet_max = settings.CODE_EXECUTOR.get('SNIPPET_MAX', 10240)


class CodeExecutionError(Exception):
    """代码执行异常"""

    def __init__(self, message: str, error_type: str = 'unknown', details: dict = None):
        super().__init__(message)
        self.error_type = error_type
        self.details = details or {}


class CodeExecutionErrorTypes:
    """代码执行错误类型常量"""

    TIMEOUT = 'timeout'  # 代码执行超时
    SYNTAX_ERROR = 'syntax_error'  # 语法错误
    RUNTIME_ERROR = 'runtime_error'  # 运行时错误
    OUTPUT_FORMAT_ERROR = 'output_format_error'  # 输出格式错误（非JSON）
    COMMAND_FORMAT_ERROR = 'command_format_error'  # 命令格式错误
    COMPILATION_ERROR = 'compilation_error'  # 编译错误
    IMPORT_ERROR = 'import_error'  # 导入错误
    MEMORY_ERROR = 'memory_error'  # 内存错误
    PERMISSION_ERROR = 'permission_error'  # 权限错误
    UNKNOWN_ERROR = 'unknown_error'  # 未知错误


class CodeExecutor:
    """代码执行器 - 支持多种编程语言"""

    _process_pool = None

    @classmethod
    def _get_process_pool(cls):
        """获取或创建进程池"""
        _pool_max_workers = settings.CODE_EXECUTOR.get('POOL_SIZE', 4)
        if cls._process_pool is None:
            cls._process_pool = ProcessPoolExecutor(max_workers=_pool_max_workers)
        return cls._process_pool

    @classmethod
    def _shutdown(cls):
        if cls._process_pool:
            cls._process_pool.shutdown(wait=True)
            cls._process_pool = None

    def __init__(self):
        self.temp_dir = None
        self._create_temp_dir()
        self._language_config = self._get_language_config()
        self._player_temp_dirs = {}

    def _get_language_config(self) -> Dict[str, Dict[str, Any]]:
        """获取语言配置，支持从settings中读取"""
        default_config = {
            'python': {
                'extension': '.py',
                'command': [self._get_python_path()],
                'timeout': settings.CODE_EXECUTOR.get('EXECUTION_TIMEOUT', 5),
            },
            'javascript': {
                'extension': '.js',
                'command': [self._get_node_path()],
                'timeout': settings.CODE_EXECUTOR.get('EXECUTION_TIMEOUT', 5),
            },
            'typescript': {
                'extension': '.ts',
                'command': [self._get_typescript_command()],
                'timeout': settings.CODE_EXECUTOR.get('EXECUTION_TIMEOUT', 5),
            },
            'lua': {
                'extension': '.lua',
                'command': [self._get_lua_path()],
                'timeout': settings.CODE_EXECUTOR.get('EXECUTION_TIMEOUT', 5),
            },
            'cpp': {
                'extension': '.cpp',
                'command': [self._get_gpp_path(), '-o', '{output}', '{file}', '&&', '{output}'],
                'timeout': settings.CODE_EXECUTOR.get('EXECUTION_TIMEOUT', 5),
                'compile_first': True,
            },
            'c': {
                'extension': '.c',
                'command': [self._get_gcc_path(), '-o', '{output}', '{file}', '&&', '{output}'],
                'timeout': getattr(settings, 'CODE_EXECUTION_TIMEOUT', 5),
                'compile_first': True,
            },
        }

        # 允许从settings中覆盖配置
        if hasattr(settings, 'CODE_EXECUTOR_CONFIG'):
            default_config.update(settings.CODE_EXECUTOR_CONFIG)

        return default_config

    def _get_python_path(self) -> str:
        """获取Python解释器路径，自动检测可用的Python版本"""
        # 首先尝试从settings获取
        if hasattr(settings, 'PYTHON_PATH'):
            return settings.PYTHON_PATH

        # 自动检测可用的Python解释器，在Windows上优先使用python
        import platform
        if platform.system() == 'Windows':
            python_candidates = ['python', 'python3']
        else:
            python_candidates = ['python3', 'python']

        for python_cmd in python_candidates:
            python_path = shutil.which(python_cmd)
            if python_path:
                return python_cmd

        # 如果都找不到，返回默认的python
        logger.warning('No Python interpreter found, using default "python"')
        return 'python'

    def _get_node_path(self) -> str:
        """获取Node.js路径"""
        return getattr(settings, 'NODE_PATH', 'node')

    def _get_ts_node_path(self) -> str:
        """获取ts-node路径"""
        # 首先尝试从settings获取
        if hasattr(settings, 'TS_NODE_PATH'):
            return settings.TS_NODE_PATH

        # 尝试使用shutil.which查找
        ts_node_path = shutil.which('ts-node')
        if ts_node_path:
            return ts_node_path

        # 在Windows上，直接检查常见的npm全局安装路径
        import platform
        if platform.system() == 'Windows':
            # 常见的npm全局安装路径
            possible_paths = [
                os.path.expanduser('~\\AppData\\Roaming\\npm\\ts-node.cmd'),
                r'C:\Program Files\nodejs\ts-node.cmd',
                r'C:\Program Files (x86)\nodejs\ts-node.cmd'
            ]

            for ts_node_cmd_path in possible_paths:
                if os.path.exists(ts_node_cmd_path):
                    return ts_node_cmd_path

        # 默认返回ts-node，让系统尝试查找
        return 'ts-node'

    def _get_typescript_command(self) -> list:
        """获取TypeScript执行命令"""
        import platform
        ts_node_path = self._get_ts_node_path()

        # 在Windows上，如果ts-node路径是.cmd文件，需要直接执行
        if platform.system() == 'Windows' and ts_node_path.endswith('.cmd'):
            return [ts_node_path]
        else:
            # 在其他系统上或者ts-node不是.cmd文件时，使用node执行
            return [self._get_node_path(), ts_node_path]

    def _get_lua_path(self) -> str:
        """获取lua路径"""
        return getattr(settings, 'LUA_PATH', 'luajit')

    def _get_gpp_path(self) -> str:
        """获取g++路径"""
        return getattr(settings, 'GPP_PATH', 'g++')

    def _get_gcc_path(self) -> str:
        """获取gcc路径"""
        return getattr(settings, 'GCC_PATH', 'gcc')

    def _get_tsc_path(self) -> str:
        """获取TypeScript编译器路径"""
        # 首先尝试从settings获取
        if hasattr(settings, 'TSC_PATH'):
            return settings.TSC_PATH

        # 尝试使用shutil.which查找
        tsc_path = shutil.which('tsc')
        if tsc_path:
            return tsc_path

        # 在Windows上，直接检查常见的npm全局安装路径
        import platform
        if platform.system() == 'Windows':
            # 常见的npm全局安装路径
            possible_paths = [
                os.path.expanduser('~\\AppData\\Roaming\\npm\\tsc.cmd'),
                r'C:\Program Files\nodejs\tsc.cmd',
                r'C:\Program Files (x86)\nodejs\tsc.cmd'
            ]

            for tsc_cmd_path in possible_paths:
                if os.path.exists(tsc_cmd_path):
                    return tsc_cmd_path

        # 默认返回tsc，让系统尝试查找
        return 'tsc'

    def _create_temp_dir(self):
        """创建临时目录"""
        try:
            self.temp_dir = tempfile.mkdtemp(prefix='code_exec_')
            logger.debug(f'Created temp directory: {self.temp_dir}')
        except Exception as e:
            logger.error(f'Failed to create temp directory: {e}')
            raise CodeExecutionError(f'无法创建临时目录: {e}')

    def _create_temp_file(self, code: str, extension: str) -> str:
        """创建临时代码文件"""
        temp_file = os.path.join(self.temp_dir, f'code_{int(time.time())}{extension}')
        with open(temp_file, 'w', encoding='utf-8') as f:
            f.write(code)

        # 如果是 TypeScript 文件，创建 package.json 和 tsconfig.json
        if extension == '.ts':
            # 创建 package.json
            package_json_path = os.path.join(self.temp_dir, 'package.json')
            with open(package_json_path, 'w', encoding='utf-8') as f:
                f.write("""
{
  "name": "ts-execution",
  "version": "1.0.0",
  "devDependencies": {
    "@types/node": "^20.0.0",
    "typescript": "^5.0.0"
  }
}
""")

            # 创建 tsconfig.json
            tsconfig_path = os.path.join(self.temp_dir, 'tsconfig.json')
            with open(tsconfig_path, 'w', encoding='utf-8') as f:
                f.write("""
{
  "compilerOptions": {
    "target": "es2020",
    "module": "commonjs",
    "lib": ["ES2020", "dom"],
    "moduleResolution": "node",
    "esModuleInterop": true,
    "outDir": "./dist",
    "allowJs": true,
    "allowCircularReferences": true,
    "skipLibCheck": true,
    "noImplicitAny": false,
    "typeRoots": ["./node_modules/@types"],
    "types": []
  }
}
""")

            # 创建简单的Node.js类型声明文件
            node_types_path = os.path.join(self.temp_dir, 'node.d.ts')
            with open(node_types_path, 'w', encoding='utf-8') as f:
                f.write("""
declare namespace NodeJS {
  interface WriteStream {
    write(chunk: any, encoding?: string): boolean;
  }

  interface ReadStream {
    read(): any;
    on(event: string, listener: Function): this;
    setEncoding(encoding: string): this;
    once(event: string, listener: Function): this;
  }

  interface Process {
    env: { [key: string]: string | undefined };
    argv: string[];
    cwd(): string;
    stdin: ReadStream;
    stdout: WriteStream;
    stderr: WriteStream;
    exit(code?: number): never;
  }
}

declare var process: NodeJS.Process;
declare var require: {
  (id: string): any;
  main: any;
};
declare var module: {
  exports: any;
};

declare var __dirname: string;
declare var __filename: string;

declare module "fs" {
  export function readFileSync(path: string, encoding?: string): string;
  export function writeFileSync(path: string, data: string): void;
}

declare module "path" {
  export function join(...paths: string[]): string;
  export function resolve(...paths: string[]): string;
}
""")

        return temp_file

    def _prepare_command(self, temp_file: str, config: dict, language: str) -> list:
        """准备执行命令"""
        command = config['command'].copy()

        # 替换命令中的占位符
        for i, cmd_part in enumerate(command):
            if '{file}' in cmd_part:
                command[i] = cmd_part.replace('{file}', temp_file)
            elif '{output}' in cmd_part:
                output_file = temp_file.replace(config['extension'], '')
                command[i] = cmd_part.replace('{output}', output_file)
            elif '{classname}' in cmd_part and language == 'java':
                # Java类名从文件名提取
                classname = os.path.basename(temp_file).replace('.java', '')
                command[i] = cmd_part.replace('{classname}', classname)

        # 如果命令中包含&&，需要使用shell执行
        if '&&' in command:
            return ' '.join(command)
        # 对于typescript，直接使用ts-node执行
        elif language == 'typescript':
            command.append(temp_file)
            return command
        else:
            # 添加文件路径到命令末尾（对于解释型语言）
            if not config.get('compile_first', False):
                command.append(temp_file)
            return command

    def get_supported_languages(self) -> dict:
        """获取支持的编程语言列表"""
        languages = {}

        language_config = self._get_language_config()
        for lang_key, config in language_config.items():
            languages[lang_key] = {'name': language_names.get(lang_key, lang_key.title()), 'extension': config['extension']}

        return languages

    def get_player_src_compiled_dir(self, player_id: str) -> str:
        return self._player_temp_dirs.get(player_id, None)

    def get_player_src_dir_name(self, player_id: str) -> str:
        # 替换不安全的路径字符为下划线
        for char in player_id:
            if not char.isalnum():
                player_id = player_id.replace(char, '_')
        return player_id

    def execute_multiple_js_files(self, player_id: str, files_dict: Dict[str, str], input_data: str = '') -> Dict[str, Any]:
        """
        执行多个JavaScript文件并返回结果

        Args:
            files_dict: 包含文件名和内容的字典，格式为 {"file1.js": "content1", "file2.js": "content2"}
            input_data: 输入数据

        Returns:
            包含执行结果的字典
        """

        # JavaScript特定的设置函数
        def js_setup():
            # 创建package.json
            package_json_path = os.path.join(self.temp_dir, 'package.json')
            with open(package_json_path, 'w', encoding='utf-8') as f:
                f.write("""
{
  "name": "js-execution",
  "version": "1.0.0",
  "type": "commonjs"
}
""")
            return None  # 返回None让通用函数自动查找main文件

        return self._execute_multiple_files_common(player_id, files_dict, input_data, 'javascript', setup_func=js_setup)

    def execute_multiple_ts_files(self, player_id: str, files_dict: Dict[str, str], input_data: str) -> Dict[str, Any]:
        """
        执行多个TypeScript文件并返回结果

        Args:
            files_dict: 包含文件名和内容的字典，格式为 {"file1.ts": "content1", "file2.ts": "content2"}
            input_data: 输入数据

        Returns:
            包含执行结果的字典
        """
        player_src_dir = os.path.join(self.temp_dir, self.get_player_src_dir_name(player_id))

        try:
            if files_dict:
                # 创建临时目录中的文件
                temp_files = []
                for file_name in files_dict:
                    # 创建临时文件
                    file_path = os.path.join(player_src_dir, file_name)
                    os.makedirs(os.path.dirname(file_path), exist_ok=True)

                    with open(file_path, 'w', encoding='utf-8') as f:
                        f.write(files_dict[file_name])
                    temp_files.append(file_path)

                # TypeScript编译设置
                # 创建package.json，不设置type: module
                package_json_path = os.path.join(self.temp_dir, 'package.json')
                with open(package_json_path, 'w', encoding='utf-8') as f:
                    f.write("""
{
  "name": "ts-execution",
  "version": "1.0.0",
  "devDependencies": {
    "@types/node": "^20.0.0",
    "typescript": "^5.0.0"
  }
}
""")

                tsconfig_path = os.path.join(self.temp_dir, 'tsconfig.json')
                with open(tsconfig_path, 'w', encoding='utf-8') as f:
                    f.write("""
{
  "compilerOptions": {
    "target": "es2020",
    "module": "commonjs",
    "lib": ["ES2020", "dom"],
    "moduleResolution": "node",
    "esModuleInterop": true,
    "outDir": "./dist",
    "skipLibCheck": true,
    "noImplicitAny": false,
    "typeRoots": ["./node_modules/@types"],
    "types": []
  }
}
""")

                # 创建简单的Node.js类型声明文件
                node_types_path = os.path.join(self.temp_dir, 'node.d.ts')
                with open(node_types_path, 'w', encoding='utf-8') as f:
                    f.write("""
declare namespace NodeJS {
  interface WriteStream {
    write(chunk: any, encoding?: string): boolean;
  }

  interface ReadStream {
    read(): any;
    on(event: string, listener: Function): this;
    setEncoding(encoding: string): this;
    once(event: string, listener: Function): this;
  }

  interface Process {
    env: { [key: string]: string | undefined };
    argv: string[];
    cwd(): string;
    stdin: ReadStream;
    stdout: WriteStream;
    stderr: WriteStream;
    exit(code?: number): never;
  }
}

declare var process: NodeJS.Process;
declare var require: {
  (id: string): any;
  main: any;
};
declare var module: {
  exports: any;
};

declare var __dirname: string;
declare var __filename: string;

declare module "fs" {
  export function readFileSync(path: string, encoding?: string): string;
  export function writeFileSync(path: string, data: string): void;
}

declare module "path" {
  export function join(...paths: string[]): string;
  export function resolve(...paths: string[]): string;
}
""")

                # 不需要创建入口文件，直接编译用户的文件
                # TypeScript编译器会自动处理依赖关系

                # 使用tsc编译TypeScript文件
                tsc_path = self._get_tsc_path()
                tsc_command = [tsc_path, '--project', tsconfig_path]
                tsc_result = self._run_command_with_env(tsc_command, '', 30, 'typescript', self.temp_dir, {})  # 给编译过程更长的超时时间

                if not tsc_result['success']:
                    # TypeScript编译器通常将错误信息输出到stdout
                    error_msg = tsc_result.get('output') or tsc_result.get('error') or '编译失败，未知错误'
                    raise CodeExecutionError(f'TypeScript编译失败: {error_msg}')

                # 编译成功后，执行编译后的main.js文件
                compiled_js_path = os.path.join(self.temp_dir, 'dist', 'main.js')

                # 执行编译后的JavaScript文件
                language_config = self._get_language_config()['javascript']
                command = language_config['command'] + [compiled_js_path]

                # 执行命令
                start_time = time.time()
                result = self._run_command_with_env(
                    command, input_data, language_config['timeout'], 'javascript', cwd=self.temp_dir, env={}
                )
                execution_time = time.time() - start_time

                return {
                    'success': result['success'],
                    'output': result['output'],
                    'error': result['error'],
                    'error_type': result.get('error_type', CodeExecutionErrorTypes.UNKNOWN_ERROR),
                    'error_details': result.get('error_details', {}),
                    'execution_time': round(execution_time, 3),
                    'console_output': result.get('console_output', ''),
                }

        except CodeExecutionError:
            raise
        except Exception as e:
            logger.error(f'多文件TypeScript执行异常: {str(e)}')
            raise CodeExecutionError(f'多文件执行异常: {str(e)}')

    def cleanup(self):
        """清理资源"""
        if self.temp_dir and os.path.exists(self.temp_dir):
            try:
                shutil.rmtree(self.temp_dir)
            except Exception as e:
                logger.warning(f'清理临时目录失败: {e}')

    def execute_with_template(
        self, player_id: str, files_dict: Dict[str, str], language: str, input_data: str = ''
    ) -> Dict[str, Any]:
        """
        使用系统API模板执行用户代码

        Args:
            files_dict: 用户上传的文件字典，通常只包含game目录下的文件
            language: 编程语言
            input_data: 输入数据

        Returns:
            包含执行结果的字典
        """
        from django.conf import settings

        player_src_builed = self.get_player_src_compiled_dir(player_id) is not None
        merged_files = None

        if not player_src_builed:
            # 构建API模板目录路径 - 确保BASE_DIR转换为字符串
            base_dir = str(settings.BASE_DIR)
            api_template_dir = os.path.join(base_dir, language_dir_map[language])

            if not os.path.exists(api_template_dir):
                raise CodeExecutionError(f'不支持的语言或缺少API模板: {language}')

            # 读取API模板文件
            template_files = {}

            # 递归读取模板目录中的所有文件
            for root, dirs, files in os.walk(api_template_dir):
                for file in files:
                    file_path = os.path.join(root, file)
                    rel_path = os.path.relpath(file_path, api_template_dir)

                    # 跳过非代码文件
                    if language == 'python' and not file.endswith('.py'):
                        continue
                    elif language == 'javascript' and not file.endswith('.js') and not file.endswith('.json'):
                        continue
                    elif language == 'typescript' and not file.endswith('.ts') and not file.endswith('.json'):
                        continue

                    try:
                        with open(file_path, 'r', encoding='utf-8') as f:
                            template_files[rel_path] = f.read()
                    except Exception as e:
                        logger.warning(f'读取模板文件失败 {file_path}: {e}')

            # 合并用户文件和模板文件
            merged_files = template_files

            # 用户文件覆盖或添加到game目录
            for user_file, content in files_dict.items():
                # 确保用户文件放在game目录下
                if not user_file.startswith(user_code_dir_name):
                    game_file_path = os.path.join(user_code_dir_name, user_file)
                else:
                    game_file_path = user_file
                merged_files[game_file_path] = content

        # 根据语言调用相应的多文件执行方法
        if language == 'python':
            return self.execute_multiple_py_files(player_id, merged_files, input_data)
        elif language == 'javascript':
            return self.execute_multiple_js_files(player_id, merged_files, input_data)
        elif language == 'typescript':
            return self.execute_multiple_ts_files(player_id, merged_files, input_data)
        elif language == 'lua':
            return self.execute_multiple_lua_files(player_id, merged_files, input_data)
        else:
            raise CodeExecutionError(f'不支持的语言: {language}')

    def _execute_multiple_files_common(
        self,
        player_id: str,
        files_dict: Dict[str, str],
        input_data: str,
        language: str,
        setup_func: Optional[Callable] = None,
        env: Optional[Dict] = None,
    ) -> Dict[str, Any]:
        """
        通用的多文件执行函数，处理不同语言的共同逻辑

        Args:
            files_dict: 包含文件名和内容的字典
            input_data: 输入数据
            language: 编程语言（'python', 'javascript', 'typescript'）
            setup_func: 可选的设置函数，用于语言特定的设置
            env: 可选的环境变量字典

        Returns:
            包含执行结果的字典
        """

        language_config = self._get_language_config()[language]
        main_file_path = 'main' + language_config['extension']
        player_src_dir = os.path.join(self.temp_dir, self.get_player_src_dir_name(player_id))

        try:
            if files_dict:
                # 创建临时目录中的文件
                temp_files = []
                for file_name in files_dict:
                    # 创建临时文件
                    file_path = os.path.join(player_src_dir, file_name)
                    os.makedirs(os.path.dirname(file_path), exist_ok=True)

                    with open(file_path, 'w', encoding='utf-8') as f:
                        f.write(files_dict[file_name])
                    temp_files.append(file_path)

                if setup_func:
                    if language == 'typescript':
                        setup_func(temp_files)
                    else:
                        setup_func()
                self._player_temp_dirs[player_id] = player_src_dir

            # 根据语言确定执行命令
            command = language_config['command'] + [main_file_path]

            # 执行命令
            start_time = time.time()
            result = self._run_command_with_env(
                command, input_data, language_config['timeout'], language, cwd=player_src_dir, env=env if env else {}
            )
            execution_time = time.time() - start_time

            return {
                'success': result['success'],
                'output': result['output'],
                'error': result['error'],
                'error_type': result.get('error_type', CodeExecutionErrorTypes.UNKNOWN_ERROR),
                'error_details': result.get('error_details', {}),
                'execution_time': round(execution_time, 3),
                'console_output': result.get('console_output', ''),
            }

        except CodeExecutionError:
            raise
        except Exception as e:
            logger.error(f'多文件{language}执行异常: {str(e)}')
            raise CodeExecutionError(f'多文件执行异常: {str(e)}')
        finally:
            pass

    def execute_multiple_py_files(self, player_id: str, files_dict: Dict[str, str], input_data: str) -> Dict[str, Any]:
        """
        执行多个Python文件并返回结果

        Args:
            files_dict: 包含文件名和内容的字典，格式为 {"file1.py": "content1", "file2.py": "content2"}
            input_data: 输入数据

        """

        # 设置Python特定的环境变量
        env = os.environ.copy()
        env['PYTHONPATH'] = os.path.join(self.temp_dir, self.get_player_src_dir_name(player_id))

        return self._execute_multiple_files_common(player_id, files_dict, input_data, 'python', env=env)

    def execute_multiple_lua_files(self, player_id: str, files_dict: Dict[str, str], input_data: str) -> Dict[str, Any]:
        return self._execute_multiple_files_common(player_id, files_dict, input_data, 'lua')

    def _analyze_execution_error(self, stderr: str, language: str, return_code: int) -> tuple[str, dict]:
        """
        分析代码执行错误类型

        Args:
            stderr: 标准错误输出
            language: 编程语言
            return_code: 进程返回码

        Returns:
            tuple: (错误类型, 错误详情)
        """
        stderr_lower = stderr.lower()
        error_details = {
            'return_code': return_code,
            'language': language,
            'stderr_snippet': stderr[:snippet_max],
        }

        # Python错误分析
        if language == 'python':
            if 'syntaxerror' in stderr_lower or 'invalid syntax' in stderr_lower:
                return CodeExecutionErrorTypes.SYNTAX_ERROR, error_details
            elif 'indentationerror' in stderr_lower or 'tabserror' in stderr_lower:
                return CodeExecutionErrorTypes.SYNTAX_ERROR, error_details
            elif 'importerror' in stderr_lower or 'modulenotfounderror' in stderr_lower:
                return CodeExecutionErrorTypes.IMPORT_ERROR, error_details
            elif 'memoryerror' in stderr_lower:
                return CodeExecutionErrorTypes.MEMORY_ERROR, error_details
            elif 'permissionerror' in stderr_lower or 'permission denied' in stderr_lower:
                return CodeExecutionErrorTypes.PERMISSION_ERROR, error_details
            elif any(
                error in stderr_lower
                for error in ['nameerror', 'typeerror', 'valueerror', 'attributeerror', 'keyerror', 'indexerror']
            ):
                return CodeExecutionErrorTypes.RUNTIME_ERROR, error_details

        # JavaScript/TypeScript错误分析
        elif language in ['javascript', 'typescript']:
            if 'syntaxerror' in stderr_lower or 'unexpected token' in stderr_lower:
                return CodeExecutionErrorTypes.SYNTAX_ERROR, error_details
            elif 'referenceerror' in stderr_lower or 'is not defined' in stderr_lower:
                return CodeExecutionErrorTypes.RUNTIME_ERROR, error_details
            elif 'typeerror' in stderr_lower:
                return CodeExecutionErrorTypes.RUNTIME_ERROR, error_details
            elif 'cannot find module' in stderr_lower or 'module not found' in stderr_lower:
                return CodeExecutionErrorTypes.IMPORT_ERROR, error_details
            elif 'compilation error' in stderr_lower or 'tsc' in stderr_lower:
                return CodeExecutionErrorTypes.COMPILATION_ERROR, error_details

        # Lua错误分析
        elif language == 'lua':
            if 'syntax error' in stderr_lower:
                return CodeExecutionErrorTypes.SYNTAX_ERROR, error_details
            elif 'attempt to' in stderr_lower and ('nil' in stderr_lower or 'call' in stderr_lower):
                return CodeExecutionErrorTypes.RUNTIME_ERROR, error_details

        # 通用错误分析
        if 'timeout' in stderr_lower or 'time limit' in stderr_lower:
            return CodeExecutionErrorTypes.TIMEOUT, error_details
        elif 'permission' in stderr_lower or 'access denied' in stderr_lower:
            return CodeExecutionErrorTypes.PERMISSION_ERROR, error_details
        elif 'memory' in stderr_lower or 'out of memory' in stderr_lower:
            return CodeExecutionErrorTypes.MEMORY_ERROR, error_details
        elif 'compilation' in stderr_lower or 'compile' in stderr_lower:
            return CodeExecutionErrorTypes.COMPILATION_ERROR, error_details

        # 默认为运行时错误
        return CodeExecutionErrorTypes.RUNTIME_ERROR, error_details

    def _run_command_with_env(
        self, command: list, input_data: str, timeout: int, language: str, cwd: str, env: dict
    ) -> Dict[str, Any]:
        """
        使用指定环境变量运行命令
        """
        try:
            import platform
            if platform.system() == 'Windows':
                # Windows 环境下，合并系统环境变量, 支持js
                full_env = os.environ.copy()
                full_env.update(env)
                env = full_env

            process = subprocess.Popen(
                command,
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                text=True,
                encoding='utf-8',
                errors='replace',
                cwd=cwd,
                env=env,
            )

            stdout, stderr = process.communicate(input=input_data, timeout=timeout)

            # TODO: control output in api.output like py
            console_output = stdout
            json_output = ''
            error_type = None
            error_details = {}

            if stdout:
                # 尝试从stdout提取JSON commands
                try:
                    # 按行分割stdout，寻找有效的JSON命令输出
                    stdout_lines = stdout.strip().split('\n')
                    json_output = None
                    console_lines = []

                    for line in stdout_lines:
                        line = line.strip()
                        if not line:
                            continue

                        # 检查是否是通过api.output输出的commands（带有特殊前缀）
                        if line.startswith('COMMANDS_OUTPUT:'):
                            # 提取真正的JSON内容
                            commands_json = line[len('COMMANDS_OUTPUT:'):]
                            try:
                                # 验证是否为有效的JSON格式
                                parsed = json.loads(commands_json)
                                if isinstance(parsed, list) and json_output is None:
                                    json_output = commands_json
                                else:
                                    console_lines.append(line)
                            except (json.JSONDecodeError, ValueError):
                                # JSON格式错误，归为console输出
                                console_lines.append(line)
                        else:
                            # 不是commands输出，归为console输出
                            console_lines.append(line)

                    # 合并console输出
                    console_output_parts = []
                    if console_lines:
                        console_output_parts.append('\n'.join(console_lines))
                    if stderr:
                        console_output_parts.append(stderr)
                    console_output = '\n'.join(console_output_parts)

                    # 如果没有找到有效的commands，但有stdout输出，则报错
                    if json_output is None and stdout.strip():
                        error_type = CodeExecutionErrorTypes.OUTPUT_FORMAT_ERROR
                        error_details = {
                            'exception_type': 'InvalidCommandsFormat',
                            'exception_message': '未找到有效的commands输出格式',
                            'exception_stack': '',
                            'stdout_snippet': stdout[:snippet_max],
                        }

                except Exception as e:
                    error_type = CodeExecutionErrorTypes.OUTPUT_FORMAT_ERROR
                    error_details = {
                        'exception_type': type(e).__name__,
                        'exception_message': str(e),
                        'exception_stack': traceback.format_exc(),
                        'stdout_snippet': stdout[:snippet_max],
                     }
            else:
                # 没有stdout输出，所有输出都是console输出
                console_output = stderr

            # 分析错误类型
            if process.returncode != 0 and error_type is None:
                error_type, error_details = self._analyze_execution_error(stderr, language, process.returncode)
            if process.returncode != 0 and error_type is None:
                error_type = CodeExecutionErrorTypes.UNKNOWN_ERROR


            return {
                'success': process.returncode == 0,
                'output': json_output if json_output else stdout,  # 如果没有JSON输出，使用原始stdout
                'error': stderr if process.returncode != 0 and stderr else ('用户代码出错' if error_type else ''),
                'error_type': error_type or '',
                'error_details': error_details or {},
                'console_output': console_output,
            }

        except subprocess.TimeoutExpired as e:
            process.kill()
            return {
                'success': False,
                'output': '',
                'error': f'{language}代码执行超时（{timeout}秒）',
                'error_type': CodeExecutionErrorTypes.TIMEOUT,
                'error_details': {
                    'exception_type': type(e).__name__,
                    'exception_message': str(e),
                    'exception_stack': traceback.format_exc(),
                    'timeout_seconds': timeout,
                    'language': language,
                },
                'console_output': '',
            }
        except Exception as e:
            return {
                'success': False,
                'output': '',
                'error': f'执行错误: {str(e)}',
                'error_type': CodeExecutionErrorTypes.UNKNOWN_ERROR,
                'error_details': {
                    'exception_type': type(e).__name__,
                    'exception_message': str(e),
                    'exception_stack': traceback.format_exc(),
                },
                'console_output': '',
            }

    def __del__(self):
        """析构函数，确保资源被清理"""
        self.cleanup()
